﻿using DocumentFormat.OpenXml.Packaging;
using Hubble.Tools;
using IFilterTextReader;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas.Parser;
using NPOI.HSSF.Extractor;
using NPOI.HSSF.UserModel;
using NPOI.HWPF;
using NPOI.HWPF.Extractor;
using SearchInFiles.Global;
using SearchInFiles.Lib.Search;
using SearchInFiles.Lib.Tools;
using Spire.Presentation;
using System;
using System.Data;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
using VersOne.Epub;

namespace SearchInFiles.Lib.OpenFile
{
    public class ReadDocument
    {
        public static void AddToStringBuilder(StringBuilder sb, string? Text) { if (!string.IsNullOrWhiteSpace(Text)) sb.AppendLine(Text); }
        public static bool ReadTextDocument(FileElements.FileElement DocumentElenemt, ISearcher searcher) => searcher.Search(new(File.ReadAllText(DocumentElenemt.Path, DocumentElenemt.encodingData.Value), DocumentElenemt));
        public static bool ReadWord(FileElements.FileElement DocumentElenemt, ISearcher searcher)
        {
            if (DocumentElenemt.ExtensionTyep.Equals(".doc", StringComparison.OrdinalIgnoreCase))
            {
                using (Stream fs = File.Open(DocumentElenemt.Path, FileMode.Open, FileAccess.Read, FileShare.Read))
                    return searcher.Search(new(new WordExtractor(new HWPFDocument(fs)).Text, DocumentElenemt));
            }
            else
            {
                using (WordprocessingDocument doc = WordprocessingDocument.Open(DocumentElenemt.Path, false))
                {
                    return searcher.Search(new(doc.RootPart?.RootElement?.InnerText, DocumentElenemt));
                    //StringBuilder sb = new StringBuilder();
                    //Body? body = doc.MainDocumentPart?.Document.Body;
                    //if (body == null)
                    //    return string.Empty;
                    //body.Elements<Paragraph>().ForEach(p => AddToStringBuilder(sb, p.InnerText.Trim()));
                    //body.Elements<DocumentFormat.OpenXml.Wordprocessing.Comments>().ForEach(p => AddToStringBuilder(sb, p.InnerText.Trim()));
                    //body.Elements<DocumentFormat.OpenXml.Wordprocessing.Header>().ForEach(p => AddToStringBuilder(sb, p.InnerText.Trim()));
                    //body.Elements<DocumentFormat.OpenXml.Wordprocessing.Footer>().ForEach(p => AddToStringBuilder(sb, p.InnerText.Trim()));
                }
            }
        }
        public static bool ReadExcel(FileElements.FileElement DocumentElenemt, ISearcher searcher)
        {
            bool result = false;
            if (DocumentElenemt.ExtensionTyep.Equals(".xls", StringComparison.OrdinalIgnoreCase))
            {
                using (Stream fs = File.Open(DocumentElenemt.Path, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    HSSFWorkbook hw = new HSSFWorkbook(fs);
                    try { return searcher.Search(new(new ExcelExtractor(hw).Text, DocumentElenemt)); }
                    finally { hw.Close(); }
                }
            }
            else
            {
                ReadxlsxHelper readxlsx = new ReadxlsxHelper();
                readxlsx.ReadExcel(DocumentElenemt.Path);
                foreach (ReadxlsxHelper.Page page in readxlsx.Pages)
                    if (searcher.Search(new(page.Data.ToString(), DocumentElenemt, page.Title)))
                        result = true;
            }
            return result;
            #region 备份的代码
            //else
            //{
            //    using (Stream fs = File.Open(DocumentElenemt.Path, FileMode.Open, FileAccess.Read, FileShare.Read))
            //    {
            //        using (IWorkbook wk = DocumentElenemt.ExtensionTyep.Equals(".xls", StringComparison.OrdinalIgnoreCase)
            //             ? (IWorkbook)new HSSFWorkbook(fs) : new XSSFWorkbook(fs))
            //        {
            //            //foreach (ISheet sheet in wk)
            //            //{
            //            //    AddToStringBuilder(sb, sheet.SheetName.Trim());
            //            //    foreach (NPOI.SS.UserModel.IRow row in sheet) foreach (NPOI.SS.UserModel.ICell cell in row)
            //            //            AddToStringBuilder(sb, cell.ToString()?.Trim());
            //            //}
            //        }
            //    }
            //}
            #endregion
        }
        public static bool ReadPowerPoint(FileElements.FileElement DocumentElenemt, ISearcher searcher)
        {
            bool result = false;
            StringBuilder sb = new StringBuilder();
            int Count;
            if (DocumentElenemt.ExtensionTyep.Equals(".ppt", StringComparison.OrdinalIgnoreCase))
            {
                using (Presentation ppt = new Presentation())
                {
                    ppt.LoadFromFile(DocumentElenemt.Path);
                    Count = 0;
                    foreach (ISlide item in ppt.Slides)
                    {
                        sb.Clear();
                        foreach (string txt in item.GetAllTextFrame())
                            AddToStringBuilder(sb, txt);

                        if (searcher.Search(new(sb.ToString(), DocumentElenemt, $"页码:[{++Count}]")))
                            result = true;
                    }
                }
                #region 注视的备份代码
                //Presentation presentation = new Presentation(fi.FullName);
                //ITextFrame[] textFramesSlideOne = SlideUtil.GetAllTextBoxes(presentation.Slides[0]);
                //foreach (ITextFrame item1 in textFramesSlideOne) 
                //    foreach (IParagraph item2 in item1.Paragraphs) 
                //        foreach (IPortion item3 in item2.Portions)
                //            sb.Append(item3.Text);
                //return sb.ToString();
                //PowerPointExtractor extractor = new PowerPointExtractor(fi.FullName);
                //return extractor.getText();
                #endregion
            }
            else
            {
                using (PresentationDocument pd = PresentationDocument.Open(DocumentElenemt.Path, false))
                {
                    if(searcher.Search(new(pd.PresentationPart?.NotesMasterPart?.NotesMaster.InnerText, DocumentElenemt,"备注")))
                        result = true;
                    pd?.PresentationPart?.SlideParts.ForEach(p =>
                    {
                        if (searcher.Search(new(p.Slide.InnerText, DocumentElenemt, p.Uri.ToString())))
                            result = true;
                    });
                }
            }
            return result;
        }
        public static bool ReadVisio(FileElements.FileElement DocumentElenemt, ISearcher searcher)
        {
            bool result = false;
            if (DocumentElenemt.ExtensionTyep.Equals(".vsd", StringComparison.OrdinalIgnoreCase))
            {
                DocumentElenemt.IsSupport = false;
            }
            else
            {
                XmlDocument document = new XmlDocument(); ;
                using (Package p = ZipPackage.Open(DocumentElenemt.Path, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    PackagePart[] ppc = p.GetParts().Where(p =>
                    {
                        string uri = p.Uri.ToString();
                        if (!uri.StartsWith("/visio/pages", StringComparison.OrdinalIgnoreCase) || uri.EndsWith(".rels", StringComparison.OrdinalIgnoreCase) || uri.EndsWith("pages.xml", StringComparison.OrdinalIgnoreCase))
                            return false;
                        return true;
                    }).ToArray();
                    foreach (PackagePart part in ppc)
                    {
                        using (Stream stream = part.GetStream())
                            document.Load(stream);
                        if (searcher.Search(new(document.InnerText, DocumentElenemt, part.Uri.ToString())))
                            result = true;
                    }
                }
                #region 注视掉的 ZipArchive 实现
                //using (ZipArchive zip = ZipFile.OpenRead(DocumentElenemt.Path))
                //{
                //    foreach (ZipArchiveEntry entry in zip.Entries)
                //    {
                //        if (!entry.FullName.StartsWith("visio/pages", StringComparison.OrdinalIgnoreCase) ||
                //            entry.FullName.EndsWith(".rels", StringComparison.OrdinalIgnoreCase) ||
                //            entry.FullName.EndsWith("pages.xml", StringComparison.OrdinalIgnoreCase))
                //            continue;
                //        using (Stream stream = entry.Open())
                //        using (StreamReader reader = new StreamReader(stream))
                //        {
                //            document.Load(reader);
                //            if (searcher.Search(new(document.InnerText, DocumentElenemt)))
                //                result = true;
                //        }
                //    }
                //}
                #endregion
            }
            return result;
        }
        public static bool ReadPdf(FileElements.FileElement DocumentElenemt, ISearcher searcher)
        {
            bool result = false;
            using (Stream fs = File.Open(DocumentElenemt.Path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                using (PdfReader pdfReader = new PdfReader(fs))
                {
                    using (PdfDocument pdfDocument = new PdfDocument(pdfReader))
                    {
                        int numberOfPages = pdfDocument.GetNumberOfPages();
                        for (int i = 1; i <= numberOfPages; ++i)
                        {
                            if (searcher.Search(new(PdfTextExtractor.GetTextFromPage(pdfDocument.GetPage(i)), DocumentElenemt,$"页码[{i}]")))
                                result = true;
                        }
                    }
                }

            }
            return result;
        }
        public static bool ReadEpub(FileElements.FileElement DocumentElenemt, ISearcher searcher)
        {
            bool result = false;
            StringBuilder sb = new StringBuilder();
            EpubBook book = EpubReader.ReadBook(DocumentElenemt.Path);
            AddToStringBuilder(sb, book.Author);
            AddToStringBuilder(sb, book.Title);
            AddToStringBuilder(sb, book.Description);
            searcher.Search(new(sb.ToString(), DocumentElenemt, "简介信息部分"));
            XmlDocument xmlDocument = new XmlDocument();
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            UtilityTools.SetParallelMode(book.ReadingOrder, cancellationTokenSource, 20, 6).AsUnordered()
                .ForAll(p =>
                {
                    xmlDocument.LoadXml(p.Content);
                    if (searcher.Search(new(xmlDocument.InnerText, DocumentElenemt, p.FilePath)))
                        result = true;
                });
            cancellationTokenSource.Dispose();
            return result;
        }

        public static bool IFilterTextReader(FileInfo fi, out string Result)
        {
            if (FilterReaderGet(fi, out Result))
                return true;
            else if (TextParseGet(fi, out Result))
                return true;
            return false;
            //throw new IFilterTextReaderException("没有与文件匹配的IFilter或实现");
        }
        private static bool FilterReaderGet(FileInfo fi, out string Result)
        {
            Result = string.Empty;
            FilterReaderOptions options = new FilterReaderOptions()
            {
                DisableEmbeddedContent = false,
                IncludeProperties = false,
                ReadIntoMemory = false,
                DoCleanUpCharacters = false,
            ReaderTimeout = FilterReaderTimeout.NoTimeout,
                Timeout = 0
            };
            try
            {
                using (FilterReader reader = new FilterReader(fi.OpenRead(), fi.Extension, options))
                    Result = reader.ReadToEnd();
                return true;
            }
            catch { return false; }
        }
        private static bool TextParseGet(FileInfo fi, out string Result)
        {
            Result = string.Empty;
            try
            {
                TextParse textParse = new TextParse(fi.FullName);
                Result = textParse.ConvertToString(false);
                return true;
            }
            catch { return false; }
        }
        [System.Serializable]
        public class IFilterTextReaderException : Exception
        {
            public IFilterTextReaderException() { }
            public IFilterTextReaderException(string message) : base(message) { }
            public IFilterTextReaderException(string message, Exception inner) : base(message, inner) { }
            [Obsolete]protected IFilterTextReaderException(
              System.Runtime.Serialization.SerializationInfo info,
              System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
        }
    }
}

